#include "AString.h"
#include <ctype.h>

static unsigned int SDBMHash(const char* str)
{
	unsigned int hash = 0;
 
	while (*str)
	{
		// equivalent to: hash = 65599*hash + (*str++);
		hash = (*str++) + (hash << 6) + (hash << 16) - hash;
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// RS Hash Function
static unsigned int RSHash(const char* str)
{
	unsigned int b = 378551;
	unsigned int a = 63689;
	unsigned int hash = 0;
 
	while (*str)
	{
		hash = hash * a + (*str++);
		a *= b;
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// JS Hash Function
static unsigned int JSHash(const char* str)
{
	unsigned int hash = 1315423911;
 
	while (*str)
	{
		hash ^= ((hash << 5) + (*str++) + (hash >> 2));
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// P. J. Weinberger Hash Function
static unsigned int PJWHash(const char* str)
{
	unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8);
	unsigned int ThreeQuarters	= (unsigned int)((BitsInUnignedInt  * 3) / 4);
	unsigned int OneEighth		= (unsigned int)(BitsInUnignedInt / 8);
	unsigned int HighBits		 = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
	unsigned int hash			 = 0;
	unsigned int test			 = 0;
 
	while (*str)
	{
		hash = (hash << OneEighth) + (*str++);
		if ((test = hash & HighBits) != 0)
		{
			hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
		}
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// ELF Hash Function
static unsigned int ELFHash(const char* str)
{
	unsigned int hash = 0;
	unsigned int x	= 0;
 
	while (*str)
	{
		hash = (hash << 4) + (*str++);
		if ((x = hash & 0xF0000000L) != 0)
		{
			hash ^= (x >> 24);
			hash &= ~x;
		}
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// BKDR Hash Function
static unsigned int BKDRHash(const char* str)
{
	unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
	unsigned int hash = 0;
 
	while (*str)
	{
		hash = hash * seed + (*str++);
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// DJB Hash Function
static unsigned int DJBHash(const char* str)
{
	unsigned int hash = 5381;
 
	while (*str)
	{
		hash += (hash << 5) + (*str++);
	}
 
	return (hash & 0x7FFFFFFF);
}
 
// AP Hash Function
static unsigned int APHash(const char* str)
{
	unsigned int hash = 0;
	int i;
 
	for (i=0; *str; i++)
	{
		if ((i & 1) == 0)
		{
			hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
		}
		else
		{
			hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
		}
	}
 
	return (hash & 0x7FFFFFFF);
}

unsigned int CAStringUtils::hash(const char* str)
{
	return (BKDRHash(str) ^ APHash(str));
}

bool CAStringUtils::startWith(const CAString& str, const char* with)
{
	int len = strlen(with);
	CAString s = str.substr(0, len);
	return s == with;
}

int CAStringUtils::split(const CAString& src, const char* token, strings& results, bool excludeZeroLen)
{
    int nend = 0;
    int nbegin = 0;

	int nskip = strlen(token);
	if (nskip <= 0) 
		return -1;

    while(nend != -1)
    {
        nend = src.find(token, nbegin);
		
		int nsize;
        if(nend == -1)
            nsize = src.length()-nbegin;
        else
            nsize = nend-nbegin;

		if (excludeZeroLen && nsize == 0)
		{
		}
		else
		{
			results.push_back(src.substr(nbegin, nsize));
		}

		nbegin = nend + nskip;
    }

	return results.size();
}

bool CAStringUtils::equal_nc(const CAString& a, const CAString& b)
{
	std::size_t i = 0; 
	while (true)
	{
		char ca = a[i];
		char cb = b[i];
		
		if (0 == ca && 0 == cb)
			break;

		char diff = tolower(ca) - tolower(cb);
		if (diff != 0)
		{
			return false;
		}
		i++;
	}

	return true;
}

inline int ginrange(int v, int min, int max){ return (((v) >= (min)) && ((v) <= (max))); };
inline int gisspace(int v)					{ return ((v) == ' ' || ginrange(v, 9, 13)); }
static unsigned int _toHex(const char* psz, const char** ppszEnd = null)
{
	int c;              /* current char */
	long total;         /* current total */
	
	if (NULL == psz) return 0;
	
	/* skip whitespace */
	while (gisspace((int)(unsigned char)*psz))
		++psz;

	total = 0;
	do 
	{
		c = (int)(unsigned char)*psz++;
		if (ginrange(c, '0', '9'))
			total = (total << 4) + (c - '0'); 
		else if (ginrange(c, 'a', 'F'))
			total = (total << 4) + (c - 'a' + 10); 
		else if (ginrange(c, 'A', 'F'))
			total = (total << 4) + (c - 'A' + 10); 
		else
			break;
		c = (int)(unsigned char)*psz++;		/* get next char */
	}
	while(true);
	
	if (ppszEnd)
	{
		*ppszEnd = psz - 1;
	}
	
	return total;   /* return result, negated if necessary */
}

bool CAStringUtils::toColor(const CAString& src, unsigned int& color)
{
	size_t len = src.length();
	const char* psz = src.c_str();
	if (len > 1 && *psz == '#') 
	{
		color = _toHex(psz + 1);
	}
	else if (len > 2 && *psz == '0' && *(psz + 1) == 'x')
	{
		color = _toHex(psz + 2);
	}
	else
	{
		color = atoi(psz);
	}
	return true;
}

bool CAStringUtils::toBool(const CAString& src, bool& result)
{
	if (CAStringUtils::equal_nc(src, "true") || CAStringUtils::equal_nc(src, "yes") || CAStringUtils::equal_nc(src, "1"))
		result = true;
	else
		result = false;
	return true;
}

#define IFMULTI 1000000
static inline float ATOF(const CAString& src) 
{
	int index = src.find("%");
	if (index > 0)
	{
		//this is a percent
		return (float)(atof(src.c_str()) / 100.0);
	}
	index = src.find("~");
	if (index > 0)
	{
		//this is a range
		strings items;
		if (2 != CAStringUtils::split(src, "~", items))
		{
			_Trace("convert %s to a float failed", src.c_str());
			return 0.0f;
		}
		float f1 = ATOF(items[0]);
		float f2 = ATOF(items[1]);
		int i1 = (int)(f1 * IFMULTI);
		int i2 = (int)(f2 * IFMULTI);
		if (i2 <= i1)
			return f1;
		i1 = i1 + rand() % (i2 - i1);
		f1 = (float)i1 / (float)IFMULTI;
		return f1;
	}

	return (float)atof(src.c_str());
}

bool CAStringUtils::toInt(const CAString& src, int& result)
{
	if (src.length() <= 0)
	{
		result = 0;
		return true;
	}
	result = atoi(src.c_str());
	return true;
}


bool CAStringUtils::toFloat(const CAString& src, float& result)
{
	if (src.length() <= 0)
	{
		result = 0.0f;
		return true;
	}
	result = ATOF(src);
	return true;
}

bool CAStringUtils::toPoint(const CAString& src, CCPoint& result)
{
	strings items;
	if (2 != split(src, ",", items))
	{
		_Trace("can not treat [%s] as point", src.c_str());
		return false;
	}
	result.x = ATOF(items[0]);
	result.y = ATOF(items[1]);
	return true;
}

bool CAStringUtils::toPoint3(const CAString& src, float& x, float& y, float& z)
{
	strings items;
	if (3 != split(src, ",", items))
	{
		_Trace("can not treat [%s] as point", src.c_str());
		return false;
	}
	x = ATOF(items[0]);
	y = ATOF(items[1]);
	z = ATOF(items[2]);
	return true;
}

void CAStringUtils::replace(CAString& str, const CAString &strsrc, const CAString &strdst)
{
	CAString::size_type pos = 0;
	CAString::size_type srclen = strsrc.size();
	CAString::size_type dstlen = strdst.size();

	while ((pos = str.find(strsrc, pos)) != CAString::npos )
	{
		str.replace( pos, srclen, strdst );
		pos += dstlen;
	}
} 

bool CAStringUtils::toSize(const CAString& src, CCSize& result)
{ 
	CCPoint pt;
	if (!toPoint(src, pt))
	{
		_Trace("can not treat [%s] as size", src.c_str());
		return false;
	}
	result.width = pt.x;
	result.height= pt.y;
	return true;
}

bool CAStringUtils::toRect(const CAString& src, CCRect& result)
{
	strings items;
	if (4 != split(src, ",", items))
	{
		_Trace("can not treat [%s] as rect", src.c_str());
		return false;
	}
	result.origin.x = ATOF(items[0]);
	result.origin.y = ATOF(items[1]);
	result.size.width = ATOF(items[2]);
	result.size.height = ATOF(items[3].c_str());
	return true;
}

static int s_nTemp = 1;
void CAStringUtils::buildTempName(CAString& name, const char* prefix)
{
	char temp[128];
	sprintf(temp, "%s_%04d", prefix, s_nTemp++);
	name = temp;
}
